﻿
namespace Patterns4Net.ArchitectureExplorer.Views.Utils
{
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;

    /// <summary>
    /// Implementation of the <see cref="TextBlock"/> control that supports source code content.
    /// Text that is assigned through property <see cref="Code"/> is formatted as source code.
    /// </summary>
    /// <remarks>
    /// <para>
    /// Currently formatting supports only indentation resizing, 
    /// but e. g. syntax highlighting may be added in the future.
    /// </para>
    /// </remarks>
    public class CodeTextBlock : TextBlock
    {
        public static readonly DependencyProperty CodeProperty =
            DependencyProperty.Register(
                "Code", 
                typeof(string), 
                typeof(CodeTextBlock), 
                new PropertyMetadata { PropertyChangedCallback = CodeChanged });        

        /// <summary>
        /// Gets or sets the code, which will be assigned to <see cref="TextBlock.Text"/>, but 
        /// before that it will be formatted.
        /// </summary>
        public string Code
        {
            get { return (string)GetValue(CodeProperty); }
            set { SetValue(CodeProperty, value); }
        }

        private static void CodeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is TextBlock && e.NewValue is string)
            {
                var code = (string)e.NewValue;
                ((TextBlock)d).Text = TrimLines(code);
            }
        }

        internal static string TrimLines(string content)
        {
            var result = new StringBuilder();
            var lines = content.Trim('\n').Replace("\t", "  ").Split('\n');  // get lines with tabs replaced by spaces.
            int shortestIndent = lines.Where(l => l.Length > 0)
                .Min(l => l.Length - l.TrimStart().Length); // calculate the shortest indentation

            foreach (var line in lines)
            {
                result.AppendLine(line.Substring(shortestIndent));
            }

            return result.ToString();
        }
    }
}
